package debtbundler.presentation.balancesheeteditor;


import static org.junit.Assert.*;

import java.awt.event.ActionEvent;

import javax.swing.JCheckBox;
import javax.swing.JFormattedTextField;

import org.junit.*;


import debtbundler.domain.entity.Payment;
import debtbundler.domain.entity.SharedCost;
import debtbundler.domain.entity.Person;
import debtbundler.domain.entity.Share;
import debtbundler.domain.entity.impl.EntityManager;
import debtbundler.presentation.balancesheeteditor.TransactionEditor;

public class PaymentAndShareEditorTest {
	
	private TestMoneyFlowEditorPanel editor;
	private Person person;
	private SharedCost sharedCost;
	
	@BeforeClass 
	public static void enableLogging() {
		debtbundler.logging.ConfigurationReader.setDefaultConf();
	}

	@Before
	public void setUp() throws Exception {
		person = EntityManager.createPerson();
		sharedCost = EntityManager.createSharedCost();
	}

	@After
	public void tearDown() throws Exception {
	}
	
	
	/**
	 * When initialized for person and person without existing flows between them,
	 * the editor must create a payment and "own share" flow.
	 */
	@Test 
	public void testInitWithoutFlows() {
		editor = new TestMoneyFlowEditorPanel(person, sharedCost);
		assertEquals("One payment must be created", 1, person.getPayments().size());
		assertEquals("One share must be created", 1, person.getShares().size());
		assertEquals("One payment must be created", 1, sharedCost.getPayments().size());
		assertEquals("One share must be created", 1, sharedCost.getShares().size());
	}

	/**
	 * When there exists two existing flows, the editor must use them.
	 * It must also pick the right ones to to use as payment and own share,
	 * if their values allow distinguishing between them.
	 */
	@Test
	public void testInitWithTwoExistingFlows() {
		Payment payment = EntityManager.createPayment(person, sharedCost);
		payment.setValue(10);
		Share share = EntityManager.createShare(person, sharedCost);
		share.setValue(5);
		
		editor = new TestMoneyFlowEditorPanel(person, sharedCost);
		assertEquals("Must use existing payment in editor", payment, editor.getCost());
		assertEquals("Must use existing share in editor", share, editor.getShare());
	}	

	/**
	 * When there exists more two costs or shares, the editor must throw an exception.
	 */
	@Test(expected=IllegalArgumentException.class)
	public void testInitWithThreeExistingFlows() {
		EntityManager.createPayment(person, sharedCost);
		EntityManager.createPayment(person, sharedCost);
		EntityManager.createPayment(person, sharedCost);
		editor = new TestMoneyFlowEditorPanel(person, sharedCost);
		fail("Not allowed to create editor for more than three payments or shares");
	}	
	
	/**
	 * Test that when not participating, the person must have no payments or shares for 
	 * a cost and that when participating, the person must have 
	 */
	@Test
	public void testParticipatesButton() {
		editor = new TestMoneyFlowEditorPanel(person, sharedCost);
				
		editor.getParticipationButton().setSelected(false);
		assertFalse("Payment field must be disabled when not participating", editor.getCostField().isEnabled());
		assertFalse("Own share field must be disabled when not participating", editor.getShareField().isEnabled());
		assertEquals("No payments when not participating", 0, person.getPayments().size());
		assertEquals("No shares when not participating", 0, person.getShares().size());
		assertEquals("No payments when not participating", 0, sharedCost.getPayments().size());
		assertEquals("No shares when not participating", 0, sharedCost.getShares().size());
		
		editor.getParticipationButton().setSelected(true);
		assertTrue("Payment field must be enabled when participating", editor.getCostField().isEnabled());
		assertTrue("Own share field must be enabled when participating", editor.getShareField().isEnabled());
		assertEquals("One payment when participating", 1, person.getPayments().size());
		assertEquals("One share when participating", 1, person.getShares().size());
		assertEquals("One payment when participating", 1, sharedCost.getPayments().size());
		assertEquals("One share when participating", 1, sharedCost.getShares().size());
		
	}
	
	@Test
	public void testCostField() {
		editor = new TestMoneyFlowEditorPanel(person, sharedCost);
		editor.getCostField().setValue( new Double(10.5) );
		editor.actionPerformed( new ActionEvent(editor.getCostField(), 1, "set value") );
		
		assertEquals(10.5, person.getPayments().iterator().next().getValue(), 0);
	}
	
	@Test 
	public void testOwnShareField() {
		editor = new TestMoneyFlowEditorPanel(person, sharedCost);
		editor.getShareField().setValue( new Double(5.0) );
		editor.actionPerformed( new ActionEvent(editor.getShareField(), 1, "set value") );
		
		assertEquals(5.0, person.getShares().iterator().next().getValue(), 0);
	}
	
	@SuppressWarnings("serial")
	class TestMoneyFlowEditorPanel extends TransactionEditor {

		TestMoneyFlowEditorPanel(Person person, SharedCost pool) {
			super(person, pool);
		}
		
		public Share getShare() {
			return this.share;
		}

		public Payment getCost() {
			return this.payment;
		}

		JCheckBox getParticipationButton() {
			return this.participationButton;
		}
		
		JFormattedTextField getCostField() {
			return this.paymentField;
		}
		
		JFormattedTextField getShareField() {
			return this.shareField;
		}
		
	}

}
